package com.audaque.springboot.foshanupload.web.webdemo.service.impl;

import com.audaque.springboot.foshanupload.web.webdemo.model.bo.TreeNodeBo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zhongguobin
 * @date 2024-04-03 17:30
 * @description TODO
 */
@Slf4j
@Service
public class TreeService {





    public void deleteById(TreeNodeBo tree, int id) {
        List<TreeNodeBo> sonList = tree.getChildren();
        if (sonList == null || sonList.isEmpty()) {
            return;
        } else {
            for (int i = 0; i < sonList.size(); i++) {
                if(Objects.equals(Integer.valueOf(sonList.get(i).getId()),Integer.valueOf(id))){
                    sonList.remove(i);
                    deleteById(new TreeNodeBo(),id);
                }else{
                    deleteById(sonList.get(i), id);
                }
            }
        }
    }


    public List<TreeNodeBo> tree2NoLeaf(TreeNodeBo treeNodeBo) {
        List<TreeNodeBo> list = new ArrayList<>();
        if (treeNodeBo == null) {
            return list;
        }
        if(!treeNodeBo.getChildren().isEmpty()){
            list.add(treeNodeBo);
            for (TreeNodeBo child :treeNodeBo.getChildren() ) {
                list.addAll(tree2NoLeaf(child));
            }
        }
        return list;

    }


    public List<TreeNodeBo> tree2leaf(TreeNodeBo treeNodeBo) {
        List<TreeNodeBo> list = new ArrayList<>();
        if (treeNodeBo == null) {
            return list;
        }
        if(treeNodeBo.getChildren().isEmpty()){
            list.add(treeNodeBo);
        }else{
            for (TreeNodeBo child :treeNodeBo.getChildren() ) {
                list.addAll(tree2leaf(child));
            }
        }
        return list;

    }



    public void check(List<TreeNodeBo> tree, List<TreeNodeBo> checkList) {
        for (TreeNodeBo node : tree) {
            if (checkList.contains(node.getId())) {
                node.setCheck(true);
            }
            this.check(node.getChildren(), checkList);
        }
    }




    
    public List<TreeNodeBo> tree2list(List<TreeNodeBo> treeNodeBoList) {
        List<TreeNodeBo> list = new ArrayList<>();
        for (TreeNodeBo treeNodeBo : treeNodeBoList) {
            list.addAll(tree2list(treeNodeBo));
        }
        return list;
    }

    public List<TreeNodeBo> tree2list(TreeNodeBo treeNodeBo) {
        List<TreeNodeBo> list = new ArrayList<>();
        if (treeNodeBo == null) {
            return list;
        }
        list.add(treeNodeBo);
        for (TreeNodeBo child : treeNodeBo.getChildren()) {
            list.addAll(tree2list(child));
        }
        return list;

    }



    public List<TreeNodeBo> list2tree(List<TreeNodeBo> treeNodeBoList,int rootParentId) {
        List<TreeNodeBo> result = treeNodeBoList.stream()
                .filter(treeNodeBo -> Objects.equals(Integer.valueOf(treeNodeBo.getParentId()),Integer.valueOf(rootParentId)))
                .map(treeNodeBo -> setChildren(treeNodeBo, treeNodeBoList)).collect(Collectors.toList());
        return result;
    }



    public List<TreeNodeBo> list2treeAndO2O(List<TreeNodeBo> treeNodeBoList,int rootParentId) {
        List<TreeNodeBo> result = treeNodeBoList.stream()
                .filter(treeNodeBo -> Objects.equals(Integer.valueOf(treeNodeBo.getParentId()),Integer.valueOf(rootParentId)))
                .map(e -> covertNode(e, treeNodeBoList)).collect(Collectors.toList());
        return result;
    }


    /**
     * 转化并设置children属性
     */
    private TreeNodeBo covertNode(TreeNodeBo treeNodeBo, List<TreeNodeBo> treeNodeBoList) {
        TreeNodeBo node = new TreeNodeBo();
        BeanUtils.copyProperties(treeNodeBo, node);
        List<TreeNodeBo> children = treeNodeBoList.stream()
                .filter(e -> Objects.equals(e.getParentId(),treeNodeBo.getId()))
                .map(m -> covertNode(m, treeNodeBoList)).collect(Collectors.toList());
        node.setChildren(children);
        return node;
    }



    private TreeNodeBo setChildren(TreeNodeBo treeNodeBo, List<TreeNodeBo> treeNodeBoList) {
        List<TreeNodeBo> children = treeNodeBoList.stream()
                .filter(subMenu -> Objects.equals(subMenu.getParentId(),treeNodeBo.getId()))
                .map(subMenu -> setChildren(subMenu, treeNodeBoList)).collect(Collectors.toList());
        treeNodeBo.setChildren(children);
        return treeNodeBo;
    }



    public TreeNodeBo findNodeById(TreeNodeBo root, int id) {
        if (root == null) {
            return null;
        } else if (root.getId() == id) {
            return root;
        } else {
            for (TreeNodeBo child : root.getChildren()) {
                TreeNodeBo node = findNodeById(child, id);
                if (node != null) {
                    return node;
                }
            }
            return null;
        }
    }




    public List<TreeNodeBo> findNodeByLevel( int level,TreeNodeBo root) {
        List<TreeNodeBo> list = new ArrayList<>();
        if (Objects.equals(Integer.valueOf(level),Integer.valueOf(root.getLevel()))) {
            list.add(root);
        }
        if (root.getChildren() != null && root.getChildren().size() > 0) {
            for (TreeNodeBo child : root.getChildren()) {
                //把内层的结果集往上塞
                list.addAll(findNodeByLevel( level,child));
            }
        }
        return list;
    }





    public List<TreeNodeBo> findPathToNode(TreeNodeBo root, TreeNodeBo target) {
        List<TreeNodeBo> path = new ArrayList<>();
        TreeNodeBo current = target;

        while (current != root) {
            path.add(current);
            current = getParent(root, current);
        }

        path.add(root);
        Collections.reverse(path);
        return path;
    }

    public TreeNodeBo getParent(TreeNodeBo root, TreeNodeBo node) {
        for (TreeNodeBo child : root.getChildren()) {
            if (child == node) {
                return root;
            } else {
                TreeNodeBo parent = getParent(child, node);
                if (parent != null) {
                    return parent;
                }
            }
        }
        return null;
    }

    public List<Integer> collectIds(TreeNodeBo node) {
        List<Integer> ids = new ArrayList<>();
        if (node == null) {
            return ids;
        }

        ids.add(node.getId());
        for (TreeNodeBo child : node.getChildren()) {
            ids.addAll(collectIds(child));
        }

        return ids;
    }



    public static TreeNodeBo createSubtree(List<Integer> ids, TreeNodeBo node) {
        if (node == null) {
            return null;
        }
        if (ids.contains(node.getId())) {
            TreeNodeBo newTreeNodeBo = new TreeNodeBo(node.getId());
            for (TreeNodeBo child : node.getChildren()) {
                TreeNodeBo subTree = createSubtree(ids, child);
                if (subTree != null) {
                    newTreeNodeBo.addChild(subTree);
                }
            }
            return newTreeNodeBo;
        } else {
            List<TreeNodeBo> newChildren = new ArrayList<>();
            for (TreeNodeBo child : node.getChildren()) {
                TreeNodeBo subTree = createSubtree(ids, child);
                if (subTree != null) {
                    newChildren.add(subTree);
                }
            }
            if (newChildren.size() == 0) {
                return null;
            } else if (newChildren.size() == 1) {
                return newChildren.get(0);
            } else {
                TreeNodeBo newTreeNodeBo = new TreeNodeBo(node.getId());
                for (TreeNodeBo child : newChildren) {
                    newTreeNodeBo.addChild(child);
                }
                return newTreeNodeBo;
            }
        }
    }

    public  void printTree(TreeNodeBo node, String prefix) {
        if (node == null) {
            return;
        }

        System.out.println(prefix + "|-- " + node.getId());

        for (TreeNodeBo child : node.getChildren()) {
            printTree(child, prefix + "|   ");
        }
    }



}
